#pragma once

#include "../common/D3D9Plugin/D3D9Plugin.h"
#include "../common/DepthTexture/DepthTexture.h"
#include "../common/ScreenTexture/ScreenTexture.h"

extern "C" __declspec(dllexport) IDirect3D9BasePlugin* CreatePlugin(IServiceLocator& ar_ServiceLocator);

class SSAOPlugin : public D3D9Plugin
{
protected:
	IShaderSystem* shaderSystem;
	ScreenTexture* screenTexture;
	ScreenTexture* depthTexture;
	ScreenTexture* ssaoTexture;
	DepthTexture* rawDepthTexture;

	Filter* ssaoFilter;	
	IDirect3DTexture9* noiseTexture;

	bool showDepthOnly;
	bool showAOOnly;
	float nearPlane;
	float farPlane;
	float strength;
	D3DXVECTOR4 sddx;

public:

	SSAOPlugin(IServiceLocator& serviceLocator)
		: D3D9Plugin(serviceLocator, L"SSAO", L"Kewl badass viking effect")
	{
		AddUIParameter(&showDepthOnly, L"showDepthOnly", L"Show depth data only", false);
		AddUIParameter(&showAOOnly, L"showAOOnly", L"Show AO data only", false);
		AddUIParameter(&nearPlane, L"nearPlane", L"Near clipping plane", 0, 1000, 0, 0.001f);
		AddUIParameter(&farPlane, L"farPlane", L"Far clipping plane", 0, 1000, 1000, 0.001f);
		AddUIParameter(&strength, L"strength", L"AO Strength", 0, 100, 50, 0.01f);
	}

	void Activate()
	{
		shaderSystem = new ShaderSystem(mr_Device_);
		rawDepthTexture = new DepthTexture(mr_Device_, environment, *shaderSystem, "Plugins\\SSAO");
		screenTexture = new ScreenTexture(mr_Device_);
		ssaoTexture = new ScreenTexture(mr_Device_);
		depthTexture = new ScreenTexture(mr_Device_);

		D3DXCreateTextureFromFile(mr_Device_, GetAbsolutePath(L"/Plugins/SSAO/Noise.bmp").c_str(), &noiseTexture);

		filterManager->AddParameter("ScreenTexture", screenTexture->GetTexture());
		filterManager->AddParameter("RawDepthTexture", rawDepthTexture->GetTexture());
		filterManager->AddParameter("DepthTexture", depthTexture->GetTexture());
		filterManager->AddParameter("SSAOTexture", ssaoTexture->GetTexture());
		filterManager->AddParameter("NoiseTexture", noiseTexture);
		filterManager->AddParameter("NearPlane", &nearPlane);
		filterManager->AddParameter("FarPlane", &farPlane);
		filterManager->AddParameter("SDDX", &sddx);
		filterManager->AddParameter("Strength", &strength);
		ssaoFilter = filterManager->LoadFilter("SSAO.fx");

		sddx.x = 1.0f / (float)backBufferDescription.Width;
		sddx.y = 1.0f / (float)backBufferDescription.Height;
	}

	virtual void PostProcess()
	{
		screenTexture->UpdateTexture();
		rawDepthTexture->CalculateDepthBufferData();

		ssaoFilter->Render("RenderDepth");
		depthTexture->UpdateTexture();

		if(showDepthOnly) return;
	
		ssaoFilter->Render("RenderSSAO");
		ssaoTexture->UpdateTexture();

		if(showAOOnly) return;
		
		ssaoFilter->Render("Combine");
	}

	void Deactivate()
	{
		filterManager->ClearParameters();

		delete rawDepthTexture;
		delete screenTexture;
		delete ssaoTexture;
		delete depthTexture;
		delete ssaoFilter;

		delete shaderSystem;

		if(noiseTexture) noiseTexture->Release();
	}
};
